home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 16 / AMIGAplus Sonderheft 16 (1998)(ICP)(DE)[!].iso / pd / anwendungen / ispell-3.1.18src / fields.c < prev    next >
C/C++ Source or Header  |  1994-01-25  |  11KB  |  432 lines

  1. #ifndef lint
  2. static char Rcs_Id[] =
  3.     "$Id: fields.c,v 1.7 1994/01/06 05:26:37 geoff Exp $";
  4. #endif
  5.  
  6. /*
  7.  * $Log: fields.c,v $
  8.  * Revision 1.7  1994/01/06  05:26:37  geoff
  9.  * Get rid of all references to System V string routines, for portability
  10.  * (sigh).
  11.  *
  12.  * Revision 1.6  1994/01/05  20:13:43  geoff
  13.  * Add the maxf parameter
  14.  *
  15.  * Revision 1.5  1994/01/04  02:40:21  geoff
  16.  * Make the increments settable (field_line_inc and field_field_inc).
  17.  * Add support for the FLD_NOSHRINK flag.
  18.  *
  19.  * Revision 1.4  1993/09/27  17:48:02  geoff
  20.  * Fix some lint complaints and some parenthesization errors.
  21.  *
  22.  * Revision 1.3  1993/09/09  01:11:11  geoff
  23.  * Add a return value to fieldwrite.  Add support for backquotes and for
  24.  * unstripped backslashes.
  25.  *
  26.  * Revision 1.2  1993/08/26  00:02:50  geoff
  27.  * Fix a stupid null-pointer bug
  28.  *
  29.  * Revision 1.1  1993/08/25  21:32:05  geoff
  30.  * Initial revision
  31.  *
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include "config.h"
  36. #include "fields.h"
  37.  
  38. field_t *    fieldread P ((FILE * file, char * delims,
  39.                   int flags, int maxf));
  40.                 /* Read a line with fields from a file */
  41. field_t *    fieldmake P ((char * line, int allocated, char * delims,
  42.                   int flags, int maxf));
  43.                 /* Make a field structure from a line */
  44. static field_t * fieldparse P ((field_t * fieldp, char * line, char * delims,
  45.                   int flags, int maxf));
  46.                 /* Parse the fields in a line */
  47. static int    fieldbackch P ((char * str, char ** out, int strip));
  48.                 /* Process backslash sequences */
  49. int        fieldwrite P ((FILE * file, field_t * fieldp, int delim));
  50.                 /* Write a line with fields to a file */
  51. void        fieldfree P ((field_t * fieldp));
  52.                 /* Free a field returned by fieldread */
  53.  
  54. unsigned int    field_field_inc = 20; /* Increment to increase # fields by */
  55. unsigned int    field_line_inc = 512; /* Incr to increase line length by */
  56.  
  57. #ifndef USG
  58. #define strchr    index
  59. #endif /* USG */
  60.  
  61. extern void    free ();
  62. extern char *    malloc ();
  63. extern char *    realloc ();
  64. extern char *    strchr ();
  65. extern int    strlen ();
  66.  
  67. /*
  68.  * Read one line of the given file into a buffer, break it up into
  69.  * fields, and return them to the caller.  The field_t structure
  70.  * returned must eventually be freed with fieldfree.
  71.  */
  72. field_t * fieldread (file, delims, flags, maxf)
  73.     FILE *        file;    /* File to read lines from */
  74.     char *        delims;    /* Characters to use for field delimiters */
  75.     int            flags;    /* Option flags;  see fields.h */
  76.     int            maxf;    /* Maximum number of fields to parse */
  77.     {
  78.     register char *    linebuf; /* Buffer to hold the line read in */
  79.     int            linemax; /* Maximum line buffer size */
  80.     int            linesize; /* Current line buffer size */
  81.  
  82.     linebuf = (char *) malloc (field_line_inc);
  83.     if (linebuf == NULL)
  84.     return NULL;
  85.     linemax = field_line_inc;
  86.     linesize = 0;
  87.     /*
  88.      * Read in the line.
  89.      */
  90.     while (fgets (&linebuf[linesize], linemax - linesize, file)
  91.       != NULL)
  92.     {
  93.     linesize += strlen (&linebuf[linesize]);
  94.     if (linebuf[linesize - 1] == '\n')
  95.         break;
  96.     else
  97.         {
  98.         linemax += field_line_inc;
  99.         linebuf = (char *) realloc (linebuf, linemax);
  100.         if (linebuf == NULL)
  101.         return NULL;
  102.         }
  103.     }
  104.     if (linesize == 0)
  105.     {
  106.     free (linebuf);
  107.     return NULL;
  108.     }
  109.     return fieldmake (linebuf, 1, delims, flags, maxf);
  110.     }
  111.  
  112. field_t * fieldmake (line, allocated, delims, flags, maxf)
  113.     char *        line;    /* Line to make into a field structure */
  114.     int            allocated; /* NZ if line allocated with malloc */
  115.     char *        delims;    /* Characters to use for field delimiters */
  116.     int            flags;    /* Option flags;  see fields.h */
  117.     int            maxf;    /* Maximum number of fields to parse */
  118.     {
  119.     register field_t *    fieldp;    /* Structure describing the fields */
  120.     int            linesize; /* Current line buffer size */
  121.  
  122.     fieldp = (field_t *) malloc (sizeof (field_t));
  123.     if (fieldp == NULL)
  124.     return NULL;
  125.     fieldp->nfields = 0;
  126.     fieldp->linebuf = allocated ? line : NULL;
  127.     fieldp->fields = NULL;
  128.     fieldp->hadnl = 0;
  129.     linesize = strlen (line);
  130.     if (line[linesize - 1] == '\n')
  131.     {
  132.     line[--linesize] = '\0';
  133.     fieldp->hadnl = 1;
  134.     }
  135.     /*
  136.      * Shrink the line buffer if necessary.
  137.      */
  138.     if (allocated  &&  (flags & FLD_NOSHRINK) == 0)
  139.     {
  140.     line = fieldp->linebuf =
  141.       (char *) realloc (fieldp->linebuf, linesize + 1);
  142.     if (fieldp->linebuf == NULL)
  143.         {
  144.         fieldfree (fieldp);
  145.         return NULL;
  146.         }
  147.     }
  148.     return fieldparse (fieldp, line, delims, flags, maxf);
  149.     }
  150.  
  151. static field_t * fieldparse (fieldp, line, delims, flags, maxf)
  152.     register field_t *    fieldp;    /* Field structure to parse into */
  153.     register char *    line;    /* Line to be parsed */
  154.     char *        delims;    /* Characters to use for field delimiters */
  155.     int            flags;    /* Option flags;  see fields.h */
  156.     int            maxf;    /* Maximum number of fields to parse */
  157.     {
  158.     int            fieldmax; /* Max size of fields array */
  159.     char *        lineout; /* Where to store xlated char in line */
  160.     char        quote;    /* Quote character in use */
  161.  
  162.     fieldp->nfields = 0;
  163.     fieldmax =
  164.       (maxf != 0  &&  maxf < field_field_inc) ? maxf + 2 : field_field_inc;
  165.     fieldp->fields = (char **) malloc (fieldmax * sizeof (char *));
  166.     if (fieldp->fields == NULL)
  167.     {
  168.     fieldfree (fieldp);
  169.     return NULL;
  170.     }
  171.     if ((flags
  172.     & (FLD_SHQUOTES | FLD_SNGLQUOTES | FLD_BACKQUOTES | FLD_DBLQUOTES))
  173.       == FLD_SHQUOTES)
  174.     flags |= FLD_SNGLQUOTES | FLD_BACKQUOTES | FLD_DBLQUOTES;
  175.     while (1)
  176.     {
  177.     if (flags & FLD_RUNS)
  178.         {
  179.         while (*line != '\0'  &&  strchr (delims, *line) != NULL)
  180.         line++;            /* Skip runs of delimiters */
  181.         if (*line == '\0')
  182.         break;
  183.         }
  184.     fieldp->fields[fieldp->nfields] = lineout = line;
  185.     /*
  186.      * Skip to the next delimiter.  At the end of skipping, "line" will
  187.      * point to either a delimiter or a null byte.
  188.      */
  189.     if (flags
  190.       & (FLD_SHQUOTES | FLD_SNGLQUOTES | FLD_BACKQUOTES
  191.         | FLD_DBLQUOTES | FLD_BACKSLASH))
  192.         {
  193.         while (*line != '\0')
  194.         {
  195.         if (strchr (delims, *line) != NULL)
  196.             break;
  197.         else if (((flags & FLD_SNGLQUOTES)  &&  *line == '\'')
  198.           ||  ((flags & FLD_BACKQUOTES)  &&  *line == '`')
  199.           ||  ((flags & FLD_DBLQUOTES)  &&  *line == '"'))
  200.             {
  201.             if ((flags & FLD_SHQUOTES) == 0
  202.               &&  line != fieldp->fields[fieldp->nfields])
  203.             quote = '\0';
  204.             else
  205.             quote = *line;
  206.             }
  207.         else
  208.             quote = '\0';
  209.         if (quote == '\0')
  210.             {
  211.             if (*line == '\\'  &&  (flags & FLD_BACKSLASH))
  212.             {
  213.             line++;
  214.             if (*line == '\0')
  215.                 break;
  216.             line += fieldbackch (line, &lineout,
  217.               flags & FLD_STRIPQUOTES);
  218.             }
  219.             else
  220.             *lineout++ = *line++;
  221.             }
  222.         else
  223.             {
  224.             /* Process quoted string */
  225.             if ((flags & FLD_STRIPQUOTES) == 0)
  226.             *lineout++ = quote;
  227.             ++line;
  228.             while (*line != '\0')
  229.             {
  230.             if (*line == quote)
  231.                 {
  232.                 if ((flags & FLD_STRIPQUOTES) == 0)
  233.                 *lineout++ = quote;
  234.                 line++;        /* Go on past quote */
  235.                 if ((flags & FLD_SHQUOTES) == 0)
  236.                 {
  237.                 while (*line != '\0'
  238.                   &&  strchr (delims, *line) == NULL)
  239.                     line++;    /* Skip to delimiter */
  240.                 }
  241.                 break;
  242.                 }
  243.             else if (*line == '\\')
  244.                 {
  245.                 if (flags & FLD_BACKSLASH)
  246.                 {
  247.                 line++;
  248.                 if (*line == '\0')
  249.                     break;
  250.                 else
  251.                     line += fieldbackch (line, &lineout,
  252.                       flags & FLD_STRIPQUOTES);
  253.                 }
  254.                 else
  255.                 {
  256.                 *lineout++ = '\\';
  257.                 if (*++line == '\0')
  258.                     break;
  259.                 *lineout++ = *line;
  260.                 }
  261.                 }
  262.             else
  263.                 *lineout++ = *line++;
  264.             }
  265.             }
  266.         }
  267.         }
  268.     else
  269.         {
  270.         while (*line != '\0'  &&  strchr (delims, *line) == NULL)
  271.         line++;            /* Skip to delimiter */
  272.         lineout = line;
  273.         }
  274.     fieldp->nfields++;
  275.     if (*line++ == '\0')
  276.         break;
  277.     if (maxf != 0  &&  fieldp->nfields > maxf)
  278.         break;
  279.     *lineout = '\0';
  280.     if (fieldp->nfields >= fieldmax)
  281.         {
  282.         fieldmax += field_field_inc;
  283.         fieldp->fields =
  284.           (char **) realloc (fieldp->fields, fieldmax * sizeof (char *));
  285.         if (fieldp->fields == NULL)
  286.         {
  287.         fieldfree (fieldp);
  288.         return NULL;
  289.         }
  290.         }
  291.     }
  292.     /*
  293.      * Shrink the field pointers and return the field structure.
  294.      */
  295.     if ((flags & FLD_NOSHRINK) == 0  &&  fieldp->nfields >= fieldmax)
  296.     {
  297.     fieldp->fields = (char **) realloc (fieldp->fields,
  298.       (fieldp->nfields + 1) * sizeof (char *));
  299.     if (fieldp->fields == NULL)
  300.         {
  301.         fieldfree (fieldp);
  302.         return NULL;
  303.         }
  304.     }
  305.     fieldp->fields[fieldp->nfields] = NULL;
  306.     return fieldp;
  307.     }
  308.  
  309. static int fieldbackch (str, out, strip)
  310.     register char *    str;        /* First char of backslash sequence */
  311.     register char **    out;        /* Where to store result */
  312.     int            strip;        /* NZ to convert the sequence */
  313.     {
  314.     register int    ch;        /* Character being developed */
  315.     char *        origstr;    /* Original value of str */
  316.  
  317.     if (!strip)
  318.     {
  319.     *(*out)++ = '\\';
  320.     if (*str != 'x'  &&  *str != 'X'  &&  (*str < '0'  ||  *str > '7'))
  321.         {
  322.         *(*out)++ = *str;
  323.         return *str != '\0';
  324.         }
  325.     }
  326.     switch (*str)
  327.     {
  328.     case '\0':
  329.         *(*out)++ = '\0';
  330.         return 0;
  331.     case 'a':
  332.         *(*out)++ = '\007';
  333.         return 1;
  334.     case 'b':
  335.         *(*out)++ = '\b';
  336.         return 1;
  337.     case 'f':
  338.         *(*out)++ = '\f';
  339.         return 1;
  340.     case 'n':
  341.         *(*out)++ = '\n';
  342.         return 1;
  343.     case 'r':
  344.         *(*out)++ = '\r';
  345.         return 1;
  346.     case 'v':
  347.         *(*out)++ = '\v';
  348.         return 1;
  349.     case 'X':
  350.     case 'x':
  351.         /* Hexadecimal sequence */
  352.         origstr = str++;
  353.         ch = 0;
  354.         if (*str >= '0'  &&  *str <= '9')
  355.         ch = *str++ - '0';
  356.         else if (*str >= 'a'  &&  *str <= 'f')
  357.         ch = *str++ - 'a' + 0xa;
  358.         else if (*str >= 'A'  &&  *str <= 'F')
  359.         ch = *str++ - 'A' + 0xa;
  360.         if (*str >= '0'  &&  *str <= '9')
  361.         ch = (ch << 4) | (*str++ - '0');
  362.         else if (*str >= 'a'  &&  *str <= 'f')
  363.         ch = (ch << 4) | (*str++ - 'a' + 0xa);
  364.         else if (*str >= 'A'  &&  *str <= 'F')
  365.         ch = (ch << 4) | (*str++ - 'A' + 0xa);
  366.         break;
  367.     case '0':
  368.     case '1':
  369.     case '2':
  370.     case '3':
  371.     case '4':
  372.     case '5':
  373.     case '6':
  374.     case '7':
  375.         /* Octal sequence */
  376.         origstr = str;
  377.         ch = *str++ - '0';
  378.         if (*str >= '0'  &&  *str <= '7')
  379.         ch = (ch << 3) | (*str++ - '0');
  380.         if (*str >= '0'  &&  *str <= '7')
  381.         ch = (ch << 3) | (*str++ - '0');
  382.         break;
  383.     default:
  384.         *(*out)++ = *str;
  385.         return 1;
  386.     }
  387.     if (strip)
  388.     {
  389.     *(*out)++ = ch;
  390.     return str - origstr;
  391.     }
  392.     else
  393.     {
  394.     for (ch = 0;  origstr < str;  ch++)
  395.         *(*out)++ = *origstr++;
  396.     return ch;
  397.     }
  398.     }
  399.  
  400. int fieldwrite (file, fieldp, delim)
  401.     FILE *        file;    /* File to write to */
  402.     register field_t *    fieldp;    /* Field structure to write */
  403.     int            delim;    /* Delimiter to place between fields */
  404.     {
  405.     int            error;    /* NZ if an error occurs */
  406.     register int    fieldno; /* Number of field being written */
  407.  
  408.     error = 0;
  409.     for (fieldno = 0;  fieldno < fieldp->nfields;  fieldno++)
  410.     {
  411.     if (fieldno != 0)
  412.         error |= putc (delim, file) == EOF;
  413.     error |= fputs (fieldp->fields[fieldno], file) == EOF;
  414.     }
  415.     if (fieldp->hadnl)
  416.     error |= putc ('\n', file) == EOF;
  417.     return error;
  418.     }
  419.  
  420. void fieldfree (fieldp)
  421.     register field_t *    fieldp;    /* Field structure to free */
  422.     {
  423.  
  424.     if (fieldp == NULL)
  425.     return;
  426.     if (fieldp->linebuf != NULL)
  427.     free ((char *) fieldp->linebuf);
  428.     if (fieldp->fields != NULL)
  429.     free ((char *) fieldp->fields);
  430.     free ((char *) fieldp);
  431.     }
  432.